package com.fin.quant.rpc.bean;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
import org.springframework.context.annotation.Configuration;

import java.beans.Introspector;
import java.lang.reflect.Method;
import java.util.Set;

@Configuration
public class GrpcClientBeanRegistry implements BeanDefinitionRegistryPostProcessor {

    private static final String PROTO_PACKAGE = "com.fin.quant.rpc.proto"; // 从 application.yml 可以读取

    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {


        ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(false);

        // 扫描所有类
        scanner.addIncludeFilter((metadataReader, metadataReaderFactory) -> true);

        Set<BeanDefinition> candidates = scanner.findCandidateComponents(PROTO_PACKAGE);

        for (BeanDefinition bd : candidates) {
            try {
                Class<?> grpcClass = Class.forName(bd.getBeanClassName());
                if (!grpcClass.getSimpleName().endsWith("Grpc")) continue;

                Method blockingMethod = grpcClass.getMethod("newBlockingStub", io.grpc.Channel.class);
                Method asyncMethod = grpcClass.getMethod("newStub", io.grpc.Channel.class);

                String serviceName = grpcClass.getSimpleName().replace("Grpc", "");

                // BlockingStub Bean
                GenericBeanDefinition blockingBd = new GenericBeanDefinition();

                blockingBd.setBeanClass(GrpcClientFactoryBean.class);
                blockingBd.getConstructorArgumentValues().addIndexedArgumentValue(0, blockingMethod);
                blockingBd.getConstructorArgumentValues().addIndexedArgumentValue(1, serviceName);
                registry.registerBeanDefinition(Introspector.decapitalize(serviceName) + "BlockingStub", blockingBd);

                // AsyncStub Bean
                GenericBeanDefinition asyncBd = new GenericBeanDefinition();
                asyncBd.setBeanClass(GrpcClientFactoryBean.class);
                asyncBd.getConstructorArgumentValues().addIndexedArgumentValue(0, asyncMethod);
                asyncBd.getConstructorArgumentValues().addIndexedArgumentValue(1, serviceName);
                registry.registerBeanDefinition(Introspector.decapitalize(serviceName) + "AsyncStub", asyncBd);

            } catch (Exception ex) {
                throw new RuntimeException(ex);
            }
        }

    }

    @Override
    public void postProcessBeanFactory(org.springframework.beans.factory.config.ConfigurableListableBeanFactory beanFactory) throws BeansException {
    }
}